#include "ThreadPool.h"

int TaskQueueInit(TaskQueue * queue);
int EnQueue(TaskQueue *queue, int net_fd, int uid,int pwd,int id);
int DeQueue(TaskQueue *queue);


int TidArrInit(TidArr * tid_arr, int worker_num){
    tid_arr->arr = (pthread_t *)calloc(worker_num,sizeof(pthread_t));
    tid_arr->worker_num = worker_num;
    return 0;
}
int Link(int net_fd,int listen_fd,MYSQL *mysql_connect,ThreadPool *thread_pool,int uid,int pwd,int command)
{
    char begin[4]={0};
    SendTrain(net_fd,begin);

    int sockfd = accept(listen_fd,NULL,NULL);
    printf("sockfd =%d\n",sockfd);
    //函数验证token
    char sql[255] = {0};
    char pwd_file_name_buf[64] = {0};
    sprintf(sql, "select user_name from user_table where uid=%d",uid);
    SqlHandler(mysql_connect, sql, 0, pwd_file_name_buf);
    char token[209]={0};
    Token(pwd_file_name_buf,token);
    char token2[209]={0};
    RecvTrain(net_fd,token2);
    char flag[4]="0";
    if(memcmp(token,token2,209)==0)
    {
        memcpy(flag,"1",1);
        printf("验证成功\n");
        SendTrain(net_fd,flag);
        printf("%d\n",sockfd);
        pthread_mutex_lock(&thread_pool->mutex);
        EnQueue(&thread_pool->task_queue,sockfd,uid,pwd,command);
        pthread_cond_signal(&thread_pool->cond);
        pthread_mutex_unlock(&thread_pool->mutex);
    }
    else
    {
        SendTrain(net_fd,flag);
        printf("验证失败\n");
        close(sockfd);
        return 0;
    }
    return 0;
}
int Dispatch(MYSQL *mysql_connect,int net_fd, int *pwd_file_id,int command_id,ThreadPool *thread_pool,int listen_fd,int uid,int epoll_fd){
    //读取一次，根据命令类型分发

    printf("comman id = %d\n", command_id);
    switch (command_id){
    case CD:
        printf("command CD\n");
        ServerCdHandler(mysql_connect, net_fd, pwd_file_id);
        printf("command CD end\n");
        break;
    case PWD:
        printf("command PWD\n");
        ServerPwdHandler(mysql_connect, net_fd, *pwd_file_id);
        printf("command PWD end\n");
        break;
    case LS:
        printf("command LS\n");
        ServerLsHandler(mysql_connect, net_fd, *pwd_file_id);
        printf("command LS end\n");
        break;
    case PUTS:
        printf("command PUTS\n");
        EpollDel(epoll_fd, listen_fd);
        Link(net_fd,listen_fd,mysql_connect,thread_pool,uid,*pwd_file_id,command_id);
        EpollAdd(epoll_fd,listen_fd, EPOLLIN);
        //ServerPutsHandler(mysql_connect, net_fd, pwd_file_id);
        break;
    case GETS:
        printf("command GETS\n");
        EpollDel(epoll_fd, listen_fd);
        Link(net_fd,listen_fd,mysql_connect,thread_pool,uid,*pwd_file_id,command_id);
        EpollAdd(epoll_fd,listen_fd, EPOLLIN);
        //ServerGetsHandler(mysql_connect, net_fd, pwd_file_id);
        break;
    case RM:
        printf("command RM\n");
        ServerRmHandler(mysql_connect, net_fd, *pwd_file_id);
        printf("command RM end\n");
        break;
    case MKDIR:
        printf("command MKDIR\n");
        ServerMkdirHandler(mysql_connect, net_fd, *pwd_file_id);
        printf("command MKDIR end\n");
        break;
    case RMDIR:
        printf("command RMDIR\n");
        ServerRmdirHandler(mysql_connect, net_fd, *pwd_file_id);
        printf("command RMDIR end\n");
        break;
    case LOGOUT:
        printf("command LOGOUT\n");
        return 1;
    default:
        break;
    }
    return 0;
}

void *ThreadFunc(void *arg){
    ThreadPool *thread_pool = (ThreadPool *)arg;
    MYSQL *mysql_connect = (MYSQL *)calloc(1, sizeof(MYSQL));
    pthread_mutex_lock(&thread_pool->mutex);
    SqlConnectionInit(&mysql_connect);
    pthread_mutex_unlock(&thread_pool->mutex);
    int net_fd;
    int uid;
    int pwd_file_id = 0;
    int id;
    while(1){
        pthread_mutex_lock(&thread_pool->mutex);
        while(thread_pool->exit_flag == 0 && \
        thread_pool->task_queue.queue_size <= 0){
            pthread_cond_wait(&thread_pool->cond, &thread_pool->mutex);
        }
        if(thread_pool->exit_flag == 1){
            SqlConnectionClosed(&mysql_connect);
            printf("I am child, I am going to exit!\n");
            free(mysql_connect);
            pthread_mutex_unlock(&thread_pool->mutex);
            pthread_exit(NULL);
        }
        net_fd = thread_pool->task_queue.front->net_fd;
        uid = thread_pool->task_queue.front->uid;
        pwd_file_id = thread_pool->task_queue.front->pwd;
        id = thread_pool->task_queue.front->id;
        printf("I am worker, I got a netfd = %d, uid = %d\n", net_fd, uid);
        DeQueue(&thread_pool->task_queue);
        pthread_mutex_unlock(&thread_pool->mutex);
        //验证token
        //查表获得当前uid的根目录作为pwd
        if(id == GETS)
        {
            printf("开始下载\n");
            ServerGetsHandler(mysql_connect, net_fd, pwd_file_id);
            printf("下载完毕\n");
        }
        else if(id == PUTS)
        {
            printf("开始上传\n");
            ServerPutsHandler(mysql_connect, net_fd, pwd_file_id);
            printf("上传完毕\n");
        }
        close(net_fd);
    }
}

int ThreadPoolInit(ThreadPool *thread_pool, int worker_num){
    TidArrInit(&thread_pool->tid_arr, worker_num);
    TaskQueueInit(&thread_pool->task_queue);
    pthread_mutex_init(&thread_pool->mutex,NULL);
    pthread_cond_init(&thread_pool->cond,NULL);
    thread_pool->exit_flag = 0;
    for(int i = 0; i < thread_pool->tid_arr.worker_num; ++i){
        pthread_create(&thread_pool->tid_arr.arr[i], NULL, ThreadFunc, thread_pool);
    }
    return 0;
}

/*
=============TaskQueue=============
*/

int TaskQueueInit(TaskQueue * queue){
    bzero(queue, sizeof(TaskQueue));
    return 0;
}
int EnQueue(TaskQueue *queue, int net_fd, int uid,int pwd,int id){
    ServerQueueNode *new_node = (ServerQueueNode *)calloc(1, sizeof(ServerQueueNode));
    new_node->net_fd = net_fd;
    new_node->uid = uid;
    new_node->pwd = pwd;
    new_node->id = id;
    if(queue->queue_size == 0){
        queue->front = new_node;
    }else{
        queue->rear->next = new_node;
    }
    queue->rear = new_node;
    ++queue->queue_size;
    return 0;
}
int DeQueue(TaskQueue *queue){
    ServerQueueNode *temp = queue->front;
    queue->front = queue->front->next;
    if(queue->queue_size == 1){
        queue->rear = NULL;
    }
    free(temp);
    --queue->queue_size;
    return 0;
}
